package lib

import (
	"GameServer/Common/data"
	"GameServer/Common/utils"
	"GameServer/Game/errors"
	"GameServer/Game/m"
	"fmt"
	"sort"
)

func CreateHero(u *m.User) {
	// 英雄
	hero := &m.Heros{
		Uid:   u.Uid,
		Heros: make(map[int64]string),
	}
	hero.Update(hero)
	// 没有的装备
	hgno := &m.HeroGoodNotOwned{
		Uid:     u.Uid,
		GoodTid: make([]int64, 0),
	}
	// ltid := heroall.GetNotGoodTid() //复制英雄装备id
	tplList, ok := data.Filters("Goods", func(val interface{}) bool {
		tplGood := val.(data.Good)
		return tplGood.Owner > 0
	})
	if !ok {
		fmt.Println("没有找到goods配置表")
		return
	}
	for _, item := range tplList {
		itemT := item.(data.Good)
		hgno.GoodTid = append(hgno.GoodTid, int64(itemT.Id))
	}

	hgno.Update(hgno)
}

// 给英雄添加道具（装备）
func AddHeroGoods(u *m.User, goodsT data.Good, num int64, PSend func(interface{}) error) (uprop *m.UpdateProp, err error) {
	if num == 0 {
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("AddHeroGoods goods 数量为0goods tid:%d", goodsT.Id))
		return
	}
	// 移除已拥有的装备
	u.RemoveNotGoodTid(int64(goodsT.Id))

	hero, uprop := u.Heros().AddHeroGoods(goodsT, num)
	//统计玩家英雄的星星数量
	SumHeroStar(u)

	// 成就，记录获取星星数量。
	AddAchievProgress(u, data.AchievementType.Get_stars, u.StarVal())
	// 计算新兵特训
	RecruitTrainMsg(u.Uid.Hex(), 0, u.StarSum, 0, PSend)

	// 当英雄拥有所有道具，就能激活，并且拥有技能。没有技能，SkillId是0
	if hero.SkillId != 0 {
		return
	}
	// Owner：英雄的tid，英雄的道具满了，就能拥有英雄和英雄技能
	if !hero.CheckFullGoods(int64(goodsT.Owner)) {
		fmt.Println("英雄道具没满")
		return uprop, nil
	}

	// 从配置表中，获取英雄信息
	herosTpl, ok := data.Get("Heros", goodsT.Owner)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到英雄配置:heros id:%d", goodsT.Owner))
		return
	}

	heroT := herosTpl.(data.Hero)

	// 从配置表中获取英雄技能信息，根据技能id
	heroSkillTpl, ok := data.Get("HeroSkills", heroT.Skill)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到英雄技能配置:heros skill id:%d", heroT.Skill))
		return
	}

	skillT := heroSkillTpl.(data.HeroSkill)
	hero.AddSkill(int64(skillT.Id)) // 英雄添加技能

	uprop.HeroUprops = append(uprop.HeroUprops, &m.HeroUprop{Tid: hero.Tid, SkillId: hero.SkillId})

	switch int64(skillT.Type) {
	case data.HeroSkillTypeEnum.PetGet: // 获得宠物
		fmt.Println("获得宠物")
		kv, pet, upropPetInfo, err := AddPet(u, utils.Int64(skillT.Effect))
		if err != nil {
			return uprop, err
		}
		if pet != nil {
			uprop.Pets = append(uprop.Pets, pet)
		}
		if upropPetInfo != nil {
			uprop.Petinfo = upropPetInfo
		}
		if kv != nil {
			uprop.Kvs = append(uprop.Kvs, kv)
		}
	case data.HeroSkillTypeEnum.PetPlus: // 宠物进阶
		fmt.Println("宠物进阶")
		switch skillT.Effect.(type) {
		case map[string]interface{}:
			mEffect := skillT.Effect.(map[string]interface{})
			key := mEffect["key"]     // 宠物tid
			val := mEffect["value"]   //进阶值
			if key == 0 && val == 0 { // 无效值
				return nil, nil
			}
			// 宠物进阶
			uprop1, pet, err := AddPetStep(u, utils.Int64(key), utils.Int64(val))
			if err != nil {
				return uprop, err
			}
			if pet != nil {
				uprop.Pets = append(uprop.Pets, pet)
			}
			if uprop1 != nil {
				uprop.Merge(uprop1)
			}
			// 重新计算宠物星星
			SumPetStar(u)
			// 成就，记录获取星星数量。
			AddAchievProgress(u, data.AchievementType.Get_stars, u.StarVal())
			// 计算新兵特训
			RecruitTrainMsg(u.Uid.Hex(), 0, u.StarSum, 0, PSend)
		default:
			fmt.Println("无效 宠物进阶 类型 effect :", goodsT.Effect)
		}
	case data.HeroSkillTypeEnum.GridCost: // 挖矿相关辅助技能
		fmt.Println("挖矿相关辅助技能")
		switch int64(skillT.ExtType) {
		case data.HeroSkillExtTypeEnum.HandleGoldRate: // 拾起金币，增加金币
			u.HandleGoldRate += utils.Int64(skillT.Effect)
		case data.HeroSkillExtTypeEnum.TheftGoldRate: // 被偷盗，减少被偷金币
			u.TheftGoldRate += utils.Int64(skillT.Effect)
		case data.HeroSkillExtTypeEnum.FireGridRate: // 挖焦土，减少消耗金币
			u.FireGridRate += utils.Int64(skillT.Effect)
			uprop.Kvs = append(uprop.Kvs, &m.BaseKV{Key: data.GlobalEnum.FireGridRate, Val: utils.Int64(skillT.Effect)})
		default:
			fmt.Println("无效的辅助类型：", skillT.ExtType)
		}
	default:
		fmt.Println("无效的英雄技能的类型：", skillT.Type)
	}
	return
}

// 随机n个装备
func RandHeroGoodNum(u *m.User, num int, page int64) (r []int64, ok bool) {
	hgno, ok := u.GetHeroGoodNotOwned()
	if !ok {
		return
	}
	pageT := 18000000 + (page+1)*10000
	lgood := make([]int64, 0)
	for _, item := range hgno.GoodTid {
		if item >= pageT { // 限制章节
			continue
		}
		lgood = append(lgood, item)
	}
	// 道具少于num，补充道具
	if len(lgood) < num {
		// lgoodtid, _ := heroall.GetPageBelowGoodTid(page)
		lgoodtid, ok := GetPageBelowGoodTid(page)
		if !ok {
			return nil, ok
		}
		sur := num - len(lgood)
		// 随机补充章节以下的道具，包含本章节
		for i := 0; i < sur; i++ {
			ridx := utils.RandomInt(0, len(lgoodtid)-1)
			lgood = append(lgood, lgoodtid[ridx])
			lgoodtid = append(lgoodtid[:ridx], lgoodtid[ridx+1:]...)
		}
	}

	r = make([]int64, 0)
	// 随机num个道具
	for i := 0; i < num; i++ {
		ridx := utils.RandomInt(0, len(lgood)-1)
		r = append(r, lgood[ridx])
		lgood = append(lgood[:ridx], lgood[ridx+1:]...)
	}
	return
}

// 判断玩家，是否拥有该道具
func HasHeroGood(u *m.User, goodtid int64) (ok bool) {
	// herotid, ok := heroall.GetHeroTidByGoodTid(goodtid)
	tpl, ok := data.Get("Goods", uint64(goodtid))
	if !ok {
		return
	}
	tplT := tpl.(data.Good)
	hero, ok := u.Heros().GetHeroByTid(int64(tplT.Owner))
	if !ok { // 没有该英雄
		fmt.Println("没有该英雄")
		return
	}
	good, ok := hero.Goods[goodtid]
	if !ok {
		fmt.Println("没有该装备")
		return
	}
	fmt.Println("装备数量", good.Num)
	if good.Num <= 0 {
		ok = false
		return
	}
	ok = true
	return
}

// 获取章节page以下的装备tid，包括page章节
func GetPageBelowGoodTid(page int64) (r []int64, ok bool) {
	// 将page以下的章节的英雄找出来
	tplHeroList, ok := data.Filters("Heros", func(val interface{}) bool {
		hero := val.(data.Hero)
		return int64(hero.Page) <= page
	})
	if !ok {
		fmt.Println("没有找到Heros配置表")
		return
	}
	// 将所有英雄的装备找出来
	tplGoodList, ok := data.Filters("Goods", func(val interface{}) bool {
		good := val.(data.Good)
		for _, item := range tplHeroList {
			itemT := item.(data.Hero)
			if itemT.Id == good.Owner {
				return true
			}
		}
		return false
	})
	if !ok {
		fmt.Println("没有找到Goods配置表")
		return
	}
	r = make([]int64, 0)
	// 将这些英雄的装备找出来
	for _, item := range tplGoodList {
		itemT := item.(data.Good)
		r = append(r, int64(itemT.Id))
	}
	return r, true
}

// 玩家的英雄：统计所有英雄的星星总数量
func SumHeroStar(u *m.User) (r int64) {
	heros := u.Heros()
	r = 0
	// 遍历玩家所有英雄
	for _, item := range heros.Heros {
		if hero, ok := heros.GetHero(item); ok {
			// 统计英雄的所有装备的星星数量
			r += hero.GetStarNum()
		}
	}

	u.StarHero = r
	u.Update(u)
	return
}

// 获取玩家所有信息
func HeroList(u *m.User) (r []*m.Hero) {
	r = make([]*m.Hero, 0)
	heros := u.Heros()
	// 遍历玩家所有英雄
	for _, item := range heros.Heros {
		if hero, ok := heros.GetHero(item); ok {
			r = append(r, hero)
		}
	}

	sort.Slice(r, func(i int, j int) bool {
		hi := r[i]
		hj := r[j]
		return hi.Tid < hj.Tid
	})
	return
}

// 玩家英雄信息
func HerosInfo(us *m.User) (r []int64, sendCount int64) {
	uHeros := us.Heros()
	for key := range uHeros.Heros {
		r = append(r, key)
	}
	nowUnix := utils.TNow().Unix()
	// 不是同一天，需要重置赠送次数
	if !utils.IsSameDay(uHeros.GiveTime, nowUnix) {
		uHeros.SendCount = 0
		uHeros.Update(uHeros)
	}
	sendCount = uHeros.SendCount
	return
}

// 赠送英雄装备
func GiveHeroGood(from string, us *m.User, tid int64, PSend func(interface{}) error) (uProp *m.UpdateProp, err error) {
	uHeros := us.Heros()
	nowUnix := utils.TNow().Unix()
	// 每天只能赠送一次卡片
	if uHeros.SendCount > 0 {
		err = errors.NewErrcode(data.Errcode.HeroGiveAway, fmt.Sprintf("今天已经赠送"))
		return
	}
	// 获取卡片信息
	good, ok := data.Get("Goods", uint64(tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有该配表Goods，或者没有该道具 %d", tid))
		return
	}
	goodT := good.(data.Good)
	// 装备品级过高，不能赠送
	if goodT.Star >= 4 {
		err = errors.NewErrcode(data.Errcode.HeroHighGrade, fmt.Sprintf("该卡片品级过高，不能赠送 %d", tid))
		return
	}

	// 玩家身上要有此卡片
	uProp, err = uHeros.CostHeroGoods(tid, 1)
	if err != nil {
		// 扣去道具失败
		return
	}

	uHeros.GiveTime = nowUnix // 记录当天赠送的卡片时间
	uHeros.SendCount++
	uHeros.Update(uHeros)
	return
}

func GetHeroList(us *m.User) (lst []*m.Hero, sendCount int64) {
	uHeros := us.Heros()
	lst = uHeros.GetHeroList()
	nowUnix := utils.TNow().Unix()
	// 不是同一天，需要重置赠送次数
	if !utils.IsSameDay(uHeros.GiveTime, nowUnix) {
		uHeros.SendCount = 0
		uHeros.Update(uHeros)
	}
	sendCount = uHeros.SendCount
	return
}

// 重置赠送次数
func ResetHeroCount(us *m.User) {
	uHeros := us.Heros()
	uHeros.SendCount = 0
	uHeros.Update(uHeros)
}
